package com.zk.code.net;

/**
 * Created by zhoukaich on 2018/8/9.
 */
import android.util.Log;

import com.example.imgrecognition.Model.Device;
import com.example.imgrecognition.Util.ArrayUtil;

import org.litepal.crud.DataSupport;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.util.CharsetUtil;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class UdpClient {
    public static final int MessageReceived = 0x99;
    public static Channel channel;

    private static void sendMsg(ByteBuf byteBuf){
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(new UdpClientHandler(byteBuf));

        try {
            channel = b.bind(0).sync().channel();
            channel.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT2))).sync();
            //channel.closeFuture().await();
            if (!channel.closeFuture().await(1000)) {
                System.err.println("Search request timed out.");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }



    //心跳专用
    private static void startAndSend(ByteBuf byteBuf){
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .handler(new UdpClientHandler(byteBuf));

        try {
            channel = b.bind(0).sync().channel();
            channel.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT2))).sync();
            //channel.closeFuture().await();
            if (!channel.closeFuture().await(300000)) {
                System.err.println("Search request timed out.");
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }
    //后置摄像头图像对比报警  zhangzf  2018年11月17日 09:31:12
    public static void startAndSendFile1(ByteBuf msg, byte type){
        Log.e("发送数据","包fasong");
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_RCVBUF, 1024 * 1024)// 设置UDP读缓冲区为1M
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))//加上这个，里面是最大接收、发送的长度
                .handler(new UdpClientFileHandler(msg));

        try {
            Channel channels = b.bind(0).sync().channel();
            int receivLen = msg.readableBytes();
            byte[] bytes = new byte[receivLen];
            msg.readBytes(bytes);
            System.err.println("readlen--->"+receivLen);
            Device device = DataSupport.findLast(Device.class);
            String deviceId = device.getDeviceid();
            Log.e("deviceid",deviceId);
            if(receivLen<=1384){
                System.err.println("数据小于1417,直接发送");
                System.err.println("数据小于1417,直接发送");
                ByteBuf byteBuf = Unpooled.buffer();
                byteBuf.writeShort(23205);  //包头
                byteBuf.writeShort(receivLen);  //数据长度
                String str = deviceId;
                byteBuf.writeBytes(str.getBytes());
                byteBuf.writeByte(type);   //帧类型
                byteBuf.writeByte((byte)0xB5);   //报文类型
                byteBuf.writeByte((byte)0x01);   //帧序列号
                byteBuf.writeByte((byte)0x00);   //通道号
                byteBuf.writeByte((byte)0xff);   //预置位号
                byteBuf.writeShort(1);            //总包数
                byteBuf.writeShort(1);             //子包数
                byteBuf.writeBytes(bytes);        //数据
                byteBuf.writeShort(2);              //校验位
                byteBuf.writeByte((byte)0x96);      //报文尾
               /* byte[] mBytes = new byte[byteBuf.readableBytes()];
                byteBuf.readBytes(mBytes);*/
                channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
            }else {
                //去除其他的字节 实际内容长度为每个包1384字节
                List<byte[]> list = null;
                try {
                    list = ArrayUtil.spliteArray(bytes, 1384);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                short totalPac = (short) list.size();  //总包数
                //按照总包数进行遍历 按个将每个数据包发过去
                short pacNo;
                for (int i = 0; i < list.size(); i++) {
                    Thread t = new Thread();
                    t.sleep(80);
                    Log.e("发送数据包中","包顺序"+i);
                    ByteBuf byteBuf = Unpooled.buffer();
                    byteBuf.writeShort(23205);  //包头
                    byteBuf.writeShort(list.get(i).length);  //数据长度
                    //String str = SerialNumber.getDeviceNo().length()==15?SerialNumber.getDeviceNo()+"00":SerialNumber.getDeviceNo()+"0";
                    String str = deviceId;
                    byteBuf.writeBytes(str.getBytes()); //设备序列号
                    byteBuf.writeByte(type);   //帧类型
                    byteBuf.writeByte((byte) 0xB5);   //报文类型
                    byteBuf.writeByte((byte) i);   //帧序列号
                    byteBuf.writeByte((byte) 0x00);   //通道号
                    byteBuf.writeByte((byte) 0xff);   //预置位号
                    byteBuf.writeShort(totalPac);            //总包数
                    byteBuf.writeShort(i + 1);             //子包数
                    pacNo = (short) (i + 1);
                    byteBuf.writeBytes(list.get(i));   //数据
                    byteBuf.writeShort(2);              //校验位
                    byteBuf.writeByte((byte) 0x96);      //报文尾
                    /*byte[] mBytes = new byte[byteBuf.readableBytes()];
                    byteBuf.readBytes(mBytes);*/
                    channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
                    //byteBuf.release();
                    //遍历完成后 发送上传结束标志
                    if(pacNo == totalPac){
                        //sendFinish();
                    }
                }
            }
            if (!channels.closeFuture().await(5000)) {
                System.err.println("Search request timed out.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }

    //前置摄像头图像对比报警  zhangzf 2018年11月17日 09:31:00
    public static void startAndSendFile2(ByteBuf msg, byte type){
        Log.e("发送数据","包fasong");
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_RCVBUF, 1024 * 1024)// 设置UDP读缓冲区为1M
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))//加上这个，里面是最大接收、发送的长度
                .handler(new UdpClientFileHandler(msg));

        try {
            Channel channels = b.bind(0).sync().channel();
            int receivLen = msg.readableBytes();
            byte[] bytes = new byte[receivLen];
            msg.readBytes(bytes);
            System.err.println("readlen--->"+receivLen);
            Device device = DataSupport.findLast(Device.class);
            String deviceId = device.getDeviceid();
            Log.e("deviceid",deviceId);
            if(receivLen<=1384){
                System.err.println("数据小于1417,直接发送");
                System.err.println("数据小于1417,直接发送");
                ByteBuf byteBuf = Unpooled.buffer();
                byteBuf.writeShort(23205);  //包头
                byteBuf.writeShort(receivLen);  //数据长度
                String str = deviceId;
                byteBuf.writeBytes(str.getBytes());
                byteBuf.writeByte(type);   //帧类型
                byteBuf.writeByte((byte)0xB5);   //报文类型
                byteBuf.writeByte((byte)0x01);   //帧序列号
                byteBuf.writeByte((byte)0x01);   //通道号
                byteBuf.writeByte((byte)0xff);   //预置位号
                byteBuf.writeShort(1);            //总包数
                byteBuf.writeShort(1);             //子包数
                byteBuf.writeBytes(bytes);        //数据
                byteBuf.writeShort(2);              //校验位
                byteBuf.writeByte((byte)0x96);      //报文尾
               /* byte[] mBytes = new byte[byteBuf.readableBytes()];
                byteBuf.readBytes(mBytes);*/
                channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
            }else {
                //去除其他的字节 实际内容长度为每个包1384字节
                List<byte[]> list = null;
                try {
                    list = ArrayUtil.spliteArray(bytes, 1384);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                short totalPac = (short) list.size();  //总包数
                //按照总包数进行遍历 按个将每个数据包发过去
                short pacNo;
                for (int i = 0; i < list.size(); i++) {
                    Thread t = new Thread();
                    t.sleep(80);
                    Log.e("发送数据包中","包顺序"+i);
                    ByteBuf byteBuf = Unpooled.buffer();
                    byteBuf.writeShort(23205);  //包头
                    byteBuf.writeShort(list.get(i).length);  //数据长度
                    //String str = SerialNumber.getDeviceNo().length()==15?SerialNumber.getDeviceNo()+"00":SerialNumber.getDeviceNo()+"0";
                    String str = deviceId;
                    byteBuf.writeBytes(str.getBytes()); //设备序列号
                    byteBuf.writeByte(type);   //帧类型
                    byteBuf.writeByte((byte) 0xB5);   //报文类型
                    byteBuf.writeByte((byte) i);   //帧序列号
                    byteBuf.writeByte((byte) 0x01);   //通道号
                    byteBuf.writeByte((byte) 0xff);   //预置位号
                    byteBuf.writeShort(totalPac);            //总包数
                    byteBuf.writeShort(i + 1);             //子包数
                    pacNo = (short) (i + 1);
                    byteBuf.writeBytes(list.get(i));   //数据
                    byteBuf.writeShort(2);              //校验位
                    byteBuf.writeByte((byte) 0x96);      //报文尾
                    /*byte[] mBytes = new byte[byteBuf.readableBytes()];
                    byteBuf.readBytes(mBytes);*/
                    channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
                    //byteBuf.release();
                    //遍历完成后 发送上传结束标志
                    if(pacNo == totalPac){
                        //sendFinish();
                    }
                }
            }
            if (!channels.closeFuture().await(5000)) {
                System.err.println("Search request timed out.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }


    //前置摄像头上传图片==zhangzf  2018年11月16日 10:14:39
    public static void startAndSendFile(ByteBuf msg, byte type){
        Log.e("发送数据","包fasong");
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_RCVBUF, 1024 * 1024)// 设置UDP读缓冲区为1M
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))//加上这个，里面是最大接收、发送的长度
                .handler(new UdpClientFileHandler(msg));

        try {
            Channel channels = b.bind(0).sync().channel();
            int receivLen = msg.readableBytes();
            byte[] bytes = new byte[receivLen];
            msg.readBytes(bytes);
            System.err.println("readlen--->"+receivLen);
            Device device = DataSupport.findLast(Device.class);
            String deviceId = device.getDeviceid();
            Log.e("deviceid",deviceId);
            if(receivLen<=1384){
                System.err.println("数据小于1417,直接发送");
                System.err.println("数据小于1417,直接发送");
                ByteBuf byteBuf = Unpooled.buffer();
                byteBuf.writeShort(23205);  //包头
                byteBuf.writeShort(receivLen);  //数据长度
                String str = deviceId;
                byteBuf.writeBytes(str.getBytes());
                byteBuf.writeByte(type);   //帧类型
                byteBuf.writeByte((byte)0xB5);   //报文类型
                byteBuf.writeByte((byte)0x01);   //帧序列号
                byteBuf.writeByte((byte)0x01);   //通道号
                byteBuf.writeByte((byte)0xff);   //预置位号
                byteBuf.writeShort(1);            //总包数
                byteBuf.writeShort(1);             //子包数
                byteBuf.writeBytes(bytes);        //数据
                byteBuf.writeShort(2);              //校验位
                byteBuf.writeByte((byte)0x96);      //报文尾
               /* byte[] mBytes = new byte[byteBuf.readableBytes()];
                byteBuf.readBytes(mBytes);*/
                channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
            }else {
                //去除其他的字节 实际内容长度为每个包1384字节
                List<byte[]> list = null;
                try {
                    list = ArrayUtil.spliteArray(bytes, 1384);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                short totalPac = (short) list.size();  //总包数
                //按照总包数进行遍历 按个将每个数据包发过去
                short pacNo;
                for (int i = 0; i < list.size(); i++) {
                    Thread t = new Thread();
                    t.sleep(80);
                    Log.e("发送数据包中","包顺序"+i);
                    ByteBuf byteBuf = Unpooled.buffer();
                    byteBuf.writeShort(23205);  //包头
                    byteBuf.writeShort(list.get(i).length);  //数据长度
                    //String str = SerialNumber.getDeviceNo().length()==15?SerialNumber.getDeviceNo()+"00":SerialNumber.getDeviceNo()+"0";
                    String str = deviceId;
                    byteBuf.writeBytes(str.getBytes()); //设备序列号
                    byteBuf.writeByte(type);   //帧类型
                    byteBuf.writeByte((byte) 0xB5);   //报文类型
                    byteBuf.writeByte((byte) i);   //帧序列号
                    byteBuf.writeByte((byte) 0x01);   //通道号
                    byteBuf.writeByte((byte) 0xff);   //预置位号
                    byteBuf.writeShort(totalPac);            //总包数
                    byteBuf.writeShort(i + 1);             //子包数
                    pacNo = (short) (i + 1);
                    byteBuf.writeBytes(list.get(i));   //数据
                    byteBuf.writeShort(2);              //校验位
                    byteBuf.writeByte((byte) 0x96);      //报文尾
                    /*byte[] mBytes = new byte[byteBuf.readableBytes()];
                    byteBuf.readBytes(mBytes);*/
                    channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
                    //byteBuf.release();
                    //遍历完成后 发送上传结束标志
                    if(pacNo == totalPac){
                        //sendFinish();
                    }
                }
            }

           if (!channels.closeFuture().await(5000)) {
                System.err.println("Search request timed out.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }

    //后置摄像头拍照上传    zhangzf  2018年11月16日 10:12:10======================
    public static void startAndSendFileBack(ByteBuf msg, byte type){
        Log.e("发送数据","包fasong");
        EventLoopGroup group = new NioEventLoopGroup();
        Bootstrap b = new Bootstrap();
        b.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.SO_BROADCAST, true)
                .option(ChannelOption.SO_RCVBUF, 1024 * 1024)// 设置UDP读缓冲区为1M
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024)// 设置UDP写缓冲区为1M
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(65535))//加上这个，里面是最大接收、发送的长度
                .handler(new UdpClientFileHandler(msg));

        try {
            Channel channels = b.bind(0).sync().channel();
            int receivLen = msg.readableBytes();
            byte[] bytes = new byte[receivLen];
            msg.readBytes(bytes);
            System.err.println("readlen--->"+receivLen);
            Device device = DataSupport.findLast(Device.class);
            String deviceId = device.getDeviceid();
            Log.e("deviceid",deviceId);
            if(receivLen<=1384){
                System.err.println("数据小于1417,直接发送");
                System.err.println("数据小于1417,直接发送");
                ByteBuf byteBuf = Unpooled.buffer();
                byteBuf.writeShort(23205);  //包头
                byteBuf.writeShort(receivLen);  //数据长度
                String str = deviceId;
                byteBuf.writeBytes(str.getBytes());
                byteBuf.writeByte(type);   //帧类型
                byteBuf.writeByte((byte)0xB5);   //报文类型
                byteBuf.writeByte((byte)0x01);   //帧序列号
                byteBuf.writeByte((byte)0x00);   //通道号
                byteBuf.writeByte((byte)0xff);   //预置位号
                byteBuf.writeShort(1);            //总包数
                byteBuf.writeShort(1);             //子包数
                byteBuf.writeBytes(bytes);        //数据
                byteBuf.writeShort(2);              //校验位
                byteBuf.writeByte((byte)0x96);      //报文尾
                channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
            }else {
                //去除其他的字节 实际内容长度为每个包1384字节
                List<byte[]> list = null;
                try {
                    list = ArrayUtil.spliteArray(bytes, 1384);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                short totalPac = (short) list.size();  //总包数
                //按照总包数进行遍历 按个将每个数据包发过去
                short pacNo;
                for (int i = 0; i < list.size(); i++) {
                    Thread t = new Thread();
                    t.sleep(80);
                    Log.e("发送数据包中","包顺序"+i);
                    ByteBuf byteBuf = Unpooled.buffer();
                    byteBuf.writeShort(23205);  //包头
                    byteBuf.writeShort(list.get(i).length);  //数据长度
                    String str = deviceId;
                    byteBuf.writeBytes(str.getBytes()); //设备序列号
                    byteBuf.writeByte(type);   //帧类型
                    byteBuf.writeByte((byte) 0xB5);   //报文类型
                    byteBuf.writeByte((byte) i);   //帧序列号
                    byteBuf.writeByte((byte) 0x00);   //通道号
                    byteBuf.writeByte((byte) 0xff);   //预置位号
                    byteBuf.writeShort(totalPac);            //总包数
                    byteBuf.writeShort(i + 1);             //子包数
                    pacNo = (short) (i + 1);
                    byteBuf.writeBytes(list.get(i));   //数据
                    byteBuf.writeShort(2);              //校验位
                    byteBuf.writeByte((byte) 0x96);      //报文尾
                    channels.writeAndFlush(new DatagramPacket(byteBuf, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
                    //遍历完成后 发送上传结束标志
                    if(pacNo == totalPac){
                    }
                }
            }
            if (!channels.closeFuture().await(5000)) {
                System.err.println("Search request timed out.");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            group.shutdownGracefully();
        }
    }
//=========================================================================


    private static void sendFinish(){
        Observable.interval(2,3, TimeUnit.SECONDS)
                .take(5)
                .subscribe(new Observer<Long>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }
                    @Override
                    public void onNext(Long value) {
                        Log.e("发起报文结束指令","发起");
                        ByteBuf byteBuf1 = endByteBuf();
                        try {
                            channel.writeAndFlush(new DatagramPacket(byteBuf1, new InetSocketAddress(NetConfig.HOST, NetConfig.PORT))).sync();
                            byteBuf1.release();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                    }
                    @Override
                    public void onComplete() {

                    }
                });
    }

    private static ByteBuf endByteBuf(){
        ByteBuf byteBuf1 = Unpooled.buffer();
        byteBuf1.writeShort(23205);  //报文头
        byteBuf1.writeShort(4);        //长度
        Device device = DataSupport.findLast(Device.class);
        String deviceId = device.getDeviceid();
        //String str = SerialNumber.getDeviceNo()+"00";
        String str = deviceId;
        byteBuf1.writeBytes(str.getBytes());//设备id号
        byteBuf1.writeByte((byte)0xB6);    //报文类型
        byteBuf1.writeByte((byte)0x01);     //帧序列号
        byteBuf1.writeByte((byte)0x01);   //通道号
        byteBuf1.writeByte((byte)0xff);   //预置位号
        byteBuf1.writeInt((int)new Date().getTime());  //时间
        byteBuf1.writeShort(2);                      //校验位
        byteBuf1.writeByte((byte)0x96);              //报文尾
        return byteBuf1;
    }



    public static void main(String[] args){
        //startAndSend("");
    }
    public static void sendMessage(ByteBuf byteBuf){
        startAndSend(byteBuf);
    }

    public static void sendCommand(ByteBuf byteBuf){
        sendMsg(byteBuf);
    };

   /* public static void sendFile(ByteBuf msg){
        startAndSendFile(msg);
    }*/

    public Channel getChannel(){
        return channel;
    }
    public static UdpClient getInstance(){
        return udpClient.INSTANCE;
    }

    private static final class udpClient{
        static final UdpClient INSTANCE = new UdpClient();
    }





}

